package com.pg_chat.utils;

import com.pg_chat.model.PicEntity;
import org.apache.poi.util.Units;
import org.apache.poi.xdgf.util.Util;
import org.apache.poi.xwpf.converter.core.utils.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class Util1 {


    protected String regex = null;
    protected String textRule = null;
    protected String picRule = null;

    /**
     * 设置替换的规则
     * @param regex
     */
    public Util1(String regex
            , String textRule
            , String picRule) {
        this.regex = regex;
        this.textRule = textRule;
        this.picRule = picRule;
    }

    public String getRegex() {
        return regex;
    }

    public void setRegex(String regex) {
        this.regex = regex;
    }

    public String getTextRule() {
        return textRule;
    }

    public void setTextRule(String textRule) {
        this.textRule = textRule;
    }

    public String getPicRule() {
        return picRule;
    }

    public void setPicRule(String picRule) {
        this.picRule = picRule;
    }

    /**
     * 根据模板生成新word文档
     * @param in 文件流
     * @param textMap 文本替换规则
     * @param picMap 图片替换规则
     * @return document be recreate
     */
    public static XWPFDocument characterReplacer(InputStream in,
                                                 Map<String,String> textMap,
                                                 Map<String, PicEntity>picMap){
        XWPFDocument document = null;
        try{
            //第一步：获取docx解析对象
            document = new XWPFDocument(in);
            //第二步：重构XWPFDocument中 不合格的 占位符 比如：${abcd}分开为${a，b..,cd}
            refactorXWPFDocument(document);
            //第三步：解析替换文本段落对象
            replaceContent(document,textMap,picMap);

        }catch (IOException e){
            e.printStackTrace();
        }
        return document;
    }


    public static void refactorXWPFDocument(XWPFDocument doc) {
        try {
            buildParagraph(doc);
            buildTable(doc);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //重构paragraph
    public static void buildParagraph(XWPFDocument document){
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            if (matcher(paragraph.getText()).find()) {
                removeEmptyRun(paragraph);
                refactorParagraph(paragraph);
            }
        }
    }

    public static void buildTable(XWPFDocument document){
        List<XWPFTable> tables = document.getTables();
        for (XWPFTable xwpfTable : tables) {
            List<XWPFTableRow> rows = xwpfTable.getRows();
            for (XWPFTableRow row :rows){
                List<XWPFTableCell> tableCells = row.getTableCells();
                for (XWPFTableCell tableCell : tableCells){
                    List<XWPFParagraph> paragraphs = tableCell.getParagraphs();
                    for (XWPFParagraph paragraph : paragraphs){
                        if (matcher(paragraph.getText()).find()) {
                            removeEmptyRun(paragraph);
                            refactorParagraph(paragraph);
                        }
                    }
                }
            }

        }
    }

    //重构paragraph
    protected static void refactorParagraph(XWPFParagraph paragraph) {
        int start = -1;
        int end = -1;
        List<XWPFRun> runs = paragraph.getRuns();
        //int[] array = {start,end};
        List<int[]> mergeList = new ArrayList<>(runs.size());
        for(int count = 0; count < runs.size(); count++ ){
            mergeList.add(new int[]{start,end});
        }

        if (findReplaceFlagInRuns(mergeList, runs)){
            //mergeRun(paragraph,array[0],array[1]);
            // 一段内可能出现多段截断，只识别一次会有遗漏
            //倒叙合并防止index错误
            for(int count = mergeList.size(); count > 0; count--){
                int[] array = mergeList.get(count-1);
                if(array[0] != -1)
                    //array[0]=>start array[1]=>end
                    mergeRun(paragraph,array[0],array[1]);
            }
            refactorParagraph(paragraph);
        }
    }

    //通过
    protected static boolean findReplaceFlagInRuns(List<int[]> mergeList, List<XWPFRun> runs){
        Boolean isNeedRefactor = false;
        //记录缺少}的run下标
        int flag = -1;
        for (int i = 0; i < runs.size() ; i++) {
            String runText = runs.get(i).toString();
//            if ('$' == runText.charAt(0)&&'}' == runText.charAt(runText.length() - 1)){
//                continue;
//            }
//            if ('$' == runText.charAt(0)){
//                array[0] = i;
//            }
//            if ('}' == runText.charAt(runText.length() - 1)){
//                array[1] = i;
//                break;
//            }
            //预处理,剔除闭合组合
            String preProcStr = runText.replaceAll("\\$\\{(.+)\\}","");
            Boolean isStart = preProcStr.contains("${");
            Boolean isEnd = preProcStr.contains("}");
            if(isStart || isEnd) {
                //有始无终
                if(!isEnd){
                    if (flag >= 0)
                        continue;
                    mergeList.get(i)[0] = i;
                    flag = i;
                } else if (!isStart) {
                    //无始有终
                    if(flag<0)
                        continue;
                    mergeList.get(flag)[1] = i;
                    flag = -1;
                    isNeedRefactor = true;
                } else if(runText.charAt(0) == '{') {
                    mergeList.get(flag)[1] = i;
                    flag = -1;
                    isNeedRefactor = true;
                }

            }
            //特殊情况，标识符首位被截断
            else if(runText.charAt(runText.length()-1) == '$'){
                mergeList.get(i)[0] = i;
                flag = i;
            }
        }

        System.out.println("hello");
        return isNeedRefactor;
    }

    protected static Matcher matcher(String str) {
        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
        return pattern.matcher(str);
    }

    /**
     * 用于正则表达式校验
     * @param str 检测字符串
     * @param regx 正则表达式
     * @return Matcher 类
     */
    private static Matcher matcher(String str, String regx) {
        Pattern pattern = Pattern.compile(regx);
        return pattern.matcher(str);
    }

    private static Integer matchCount(String str, String regx) {
        Integer count = 0;
        Pattern pattern = Pattern.compile(regx);
        while (pattern.matcher(str).find()){
            count++;
        }
        return count;
    }

    //移除空白的run
    public static void removeEmptyRun(XWPFParagraph paragraph) {
        List<XWPFRun> runsq = paragraph.getRuns();
        for (int i = 0; i <runsq.size() ; i++) {
            String runText = runsq.get(i).toString();
            if (StringUtils.isEmpty(runText)){
                paragraph.removeRun(i);
                break;
            }
        }
        //递归进入paragraph
        for (XWPFRun xwpfRun : runsq) {
            String runText = xwpfRun.toString();
            if (StringUtils.isEmpty(runText)) {
                removeEmptyRun(paragraph);
                break;
            }
        }
    }

    //合并run
    public static void mergeRun(XWPFParagraph paragraph, int start, int end) {
        int removeCount = end-start;//删除次数
        int removeIndex = start+1;//删除开始位置

        List<XWPFRun> runs = paragraph.getRuns();
        for (XWPFRun run : runs) {
            System.out.println(run.toString());
        }
        StringBuilder sb = new StringBuilder();
        sb.append(runs.get(start).toString());

        for (int i = 0; i < removeCount; i++){
            sb.append(runs.get(removeIndex).toString());
            paragraph.removeRun(removeIndex);
        }
        runs.get(start).setText(sb.toString(),0);
    }

    public static void replaceContent(XWPFDocument document
            ,Map<String,String> textMap
            ,Map<String,PicEntity> picMap){
        //获取段落集合
        List<XWPFParagraph> paragraphs = document.getParagraphs();
        String[] runConfig;
        for(XWPFParagraph paragraph : paragraphs){
            //判断此段落时候需要进行替换
            String text = paragraph.getText();
            if(checkText(text)){
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs){
                    if(checkPic(run.toString())){
                        replacePic(run,picMap);
                    }else
                        run.setText(replaceText(run.toString(),textMap),0);
                }
            }
        }
    }

    /**
     * 判断文本中是否包含标识符
     * @param text 文本
     * @return 包含返回true,不包含返回false
     */
    public static boolean checkText(String text){
        boolean check  =  false;
        if(null != text && matcher(text).find()){
            check = true;
        }
        return check;

    }

    /**
     * 判断run中是否包含图片标志
     * @param runToString run
     * @return 包含返回true,不包含返回false
     */
    public static boolean checkPic(String runToString){
        boolean check  =  false;
        if(null != runToString && runToString.contains("${pic")){
            check = true;
        }
        return check;

    }

    /**
     * 传入的文本与textMap进行匹配
     * @param text 文本
     * @param textMap map
     * @return 处理后的文本
     */
    public static String replaceText(String text, Map<String, String>textMap){
        textMap = new HashMap<>(textMap);
            //合成标识，用于查找替换
            for(String key :packageKey(text)){
                String value = textMap.get(key);
                System.out.println("当前的文本内容: "+text+" 匹配值"+key);
                if(null != value)
                    text = insertValue(text, key, value);
            }

        //textMap中没有对应的替换值，将标识符替换为NULL
        if (checkText(text)){
            text = insertValue(text,"(.+)","NULL");
        }
        return text;
    }

    /**
     * 对run进行分析，如果存在替换值，则将图片数据输入到run
     * @param run run
     * @param picMap 图片集
     * @return run
     */
    public static XWPFRun replacePic(XWPFRun run, Map<String, PicEntity> picMap){
        String runStr = run.toString();
        for(String key : packageKey(runStr)){
            key = key.replaceAll("pic-","");
            PicEntity pic = picMap.get(key);
            System.out.println("当前的文本内容: "+runStr+" 匹配值"+key);
            if(pic != null){
                try {
                    runStr = insertValue(runStr, "pic-"+key,"");

                    run.setText(runStr,0);
                    run.addBreak();
                    run.addPicture(new ByteArrayInputStream(pic.getPic())
                            , pic.getPicType(), key
                            ,Units.pixelToEMU(pic.getWidth()),Units.pixelToEMU(pic.getHeight()));
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        if (checkText(runStr)){
            runStr = insertValue(runStr,"(.+)", "PICTURE NOT FIND!");
            run.setText(runStr,0);
        }

        return run;

    }

    /**
     * 对获取的文本进行处理，提取key值
     * @param text 文本
     * @return 处理结果
     */
    protected static List<String> packageKey(String text){
        List<String> list = new LinkedList<>();
        String regex = "\\$\\{|\\}$";
        //String regex = "\\$\\{(.+)\\}";
        Matcher matcher = matcher(text);
        while(matcher.find()){
            list.add(matcher.group(0).replaceAll(regex,""));
        }
        list.add(text);
        return list;
//        return matcher.find()
//                ? matcher.group(0).replaceAll(regex,"")
//                : list.add(text);
    }

    protected static String insertValue(String text, String key, String value){
        return text.replaceAll("\\$\\{"+key+"\\}", value);
    }
}
